//
//  DouAudioStreamPlayer.m
//  RNRecorder
//
//  Created by GJS on 2018/12/13.
//  Copyright © 2018年 Facebook. All rights reserved.
//

#import "DouAudioStreamPlayer.h"
#import "DouTrack.h"
// 豆瓣音频流播放器
#import "DOUAudioStreamer.h"
#import "DOUAudioVisualizer.h"

static void *kStatusKVOKey = &kStatusKVOKey;
static void *kDurationKVOKey = &kDurationKVOKey;
static void *kBufferingRatioKVOKey = &kBufferingRatioKVOKey;

@interface DouAudioStreamPlayer () {
@private
    
    NSTimer *_timer;
    
}

@property (nonatomic, strong) DOUAudioVisualizer *audioVisualizer;

@end

@implementation DouAudioStreamPlayer

- (void)dealloc {
    [_timer invalidate];
    [_streamer stop];
    [self _cancelStreamer];
}

- (instancetype)init {
    self = [super init];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup {
    
    _playingVolume = [DOUAudioStreamer volume];
    
    [self _resetStreamer];
    
    if (self.audioVisualizer) { // 懒加载初始化 audioVisualizer
        //
    }
}

- (void)_cancelStreamer
{
    if (_streamer != nil) {
        [_streamer pause];
        [_streamer removeObserver:self forKeyPath:@"status"];
        [_streamer removeObserver:self forKeyPath:@"duration"];
        [_streamer removeObserver:self forKeyPath:@"bufferingRatio"];
        _streamer = nil;
    }
}

- (void)_resetStreamer
{
    [self _cancelStreamer];
    
    if (0 == [_tracks count])
    {
        NSLog(@"(No tracks available)");
        self.currentPlayingTrack = nil;
    }
    else
    {
        DouTrack *track = [_tracks objectAtIndex:_currentTrackIndex];
        NSString *title = [NSString stringWithFormat:@"%@ - %@", track.artist, track.title];
        self.currentPlayingTrack = track;
        NSLog(@"track title:%@", title);
        
        _streamer = [DOUAudioStreamer streamerWithAudioFile:track];
        [_streamer addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:kStatusKVOKey];
        [_streamer addObserver:self forKeyPath:@"duration" options:NSKeyValueObservingOptionNew context:kDurationKVOKey];
        [_streamer addObserver:self forKeyPath:@"bufferingRatio" options:NSKeyValueObservingOptionNew context:kBufferingRatioKVOKey];
        
        [self play];
        
        [self _updateBufferingStatus];
        [self _setupHintForStreamer];
    }
}

#pragma mark - getter

- (BOOL)getIsPlaying {
    //BOOL b = _streamer.status == DOUAudioStreamerPlaying;
    BOOL b = _streamer && _streamer.status == DOUAudioStreamerPlaying;
    return b;
}

- (double)getDuration {
    return _streamer.duration;
}

- (DOUAudioVisualizer *)audioVisualizer {
    if (!_audioVisualizer) {
        
        //#define kBarHeight 6.0
        //#define kBarHorizontalPadding 2.0
        //#define kBarVerticalPadding 1.0
        
        //#define kDOUAudioAnalyzerLevelCount 20
        
        // _bar.verticalCount = (NSUInteger)lrint(floor(height / kBarHeight));
        
        _audioVisualizer = [[DOUAudioVisualizer alloc] initWithFrame:CGRectMake(0, 0, 1, 60)];
        [_audioVisualizer layoutSubviews]; // 因为没有视图，强制调用 layoutSubviews
        
        __weak typeof (self) weakSelf = self;
        _audioVisualizer.visualizerBlock = ^(id data) {
            //
            if (weakSelf.isPlaying) {
                NSArray *array = (NSArray *)data;
                for (NSUInteger i=0; i<array.count; i++) {
                    NSNumber *num = array[i];
                    if (i == 0) {
                        printf("\nnum:%ld", (long)num.integerValue);
                    } else {
                        printf("    %ld", (long)num.integerValue);
                    }
                }
            }
        };
    }
    
    return _audioVisualizer;
}

#pragma mark - setter

- (void)setTracks:(NSArray *)tracks {
    _tracks = tracks;
    [self _resetStreamer];
}

- (void)setPlayingProgress:(double)playingProgress {
    _playingProgress = MAX(0, MIN(1, playingProgress));
    [self _actionSliderProgress:nil];
}

- (void)setCurrentTime:(NSTimeInterval)currentTime {
    _currentTime = fmin(fmax(currentTime, 0.0), [_streamer duration]);
    [_streamer setCurrentTime:_currentTime];
}

- (void)setPlayingVolume:(double)playingVolume {
    _playingVolume = fmin(fmax(playingVolume, 0.0), 1.0);
    [self _actionSliderVolume:nil];
}

- (void)setCurrentTrackIndex:(NSUInteger)currentTrackIndex {
    _currentTrackIndex = MAX(0, MIN(currentTrackIndex, [_tracks count]));
    [self _resetStreamer];
}

- (void)play {
    [_streamer play];
    if (self.audioVisualizer) { // 懒加载确保存在
        //
    }
    if (!_timer) {
        _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(_timerAction:) userInfo:nil repeats:YES];
    } else {
        if (![_timer isValid]) {
            [_timer fire];
        }
    }
}

- (void)playNext {
    [self _actionNext:nil];
}

- (void)playTrackIndex:(NSUInteger)trackIndex {
    self.currentTrackIndex = trackIndex;
    [self play];
}

- (void)_setupHintForStreamer
{
    NSUInteger nextIndex = _currentTrackIndex + 1;
    if (nextIndex >= [_tracks count]) {
        nextIndex = 0;
    }
    
    [DOUAudioStreamer setHintWithAudioFile:[_tracks objectAtIndex:nextIndex]];
}

- (void)_timerAction:(id)timer
{
    CGFloat progress = 0.0;
    if ([_streamer duration] == 0.0) {
        progress = 0.0;
    }
    else {
        progress = [_streamer currentTime] / [_streamer duration];
    }
    NSLog(@"playing progress:%f", progress);
}

- (void)_updateStatus
{
    switch ([_streamer status]) {
        case DOUAudioStreamerPlaying:
            //[_statusLabel setText:@"playing"];
            //[_buttonPlayPause setTitle:@"Pause" forState:UIControlStateNormal];
            break;
            
        case DOUAudioStreamerPaused:
            //[_statusLabel setText:@"paused"];
            //[_buttonPlayPause setTitle:@"Play" forState:UIControlStateNormal];
            break;
            
        case DOUAudioStreamerIdle:
            //[_statusLabel setText:@"idle"];
            //[_buttonPlayPause setTitle:@"Play" forState:UIControlStateNormal];
            break;
            
        case DOUAudioStreamerFinished:
            //[_statusLabel setText:@"finished"];
            //[self _actionNext:nil];
            [self stop];
            break;
            
        case DOUAudioStreamerBuffering:
            //[_statusLabel setText:@"buffering"];
            break;
            
        case DOUAudioStreamerError:
            //[_statusLabel setText:@"error"];
            break;
    }
    
    if ([self.delegate respondsToSelector:@selector(audioStreamPlayer:updatedStatus:)]) {
        [self.delegate audioStreamPlayer:self updatedStatus:@([_streamer status])];
    }
}

- (void)_updateBufferingStatus
{
    //[_miscLabel setText:[NSString stringWithFormat:@"Received %.2f/%.2f MB (%.2f %%), Speed %.2f MB/s", (double)[_streamer receivedLength] / 1024 / 1024, (double)[_streamer expectedLength] / 1024 / 1024, [_streamer bufferingRatio] * 100.0, (double)[_streamer downloadSpeed] / 1024 / 1024]];
    
    if ([_streamer bufferingRatio] >= 1.0) {
        NSLog(@"sha256: %@", [_streamer sha256]);
    }
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (context == kStatusKVOKey) {
        [self performSelector:@selector(_updateStatus)
                     onThread:[NSThread mainThread]
                   withObject:nil
                waitUntilDone:NO];
    }
    else if (context == kDurationKVOKey) {
        [self performSelector:@selector(_timerAction:)
                     onThread:[NSThread mainThread]
                   withObject:nil
                waitUntilDone:NO];
    }
    else if (context == kBufferingRatioKVOKey) {
        [self performSelector:@selector(_updateBufferingStatus)
                     onThread:[NSThread mainThread]
                   withObject:nil
                waitUntilDone:NO];
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

- (void)pause {
    [_streamer pause];
    [_timer setFireDate:[NSDate distantFuture]];
}

- (void)stop {
    [_streamer stop];
    [_timer invalidate];
    _timer = nil;
    self.currentPlayingTrack = nil;
    if (_audioVisualizer) {
        _audioVisualizer.visualizerBlock = nil;
        [_audioVisualizer finalize];
        _audioVisualizer = nil;
    }
}

- (void)_actionPlayPause:(id)sender
{
    if ([_streamer status] == DOUAudioStreamerPaused ||
        [_streamer status] == DOUAudioStreamerIdle) {
        [_streamer play];
    }
    else {
        [_streamer pause];
    }
}

- (void)_actionNext:(id)sender
{
    if (++_currentTrackIndex >= [_tracks count]) {
        _currentTrackIndex = 0;
    }
    
    [self _resetStreamer];
}

- (void)_actionStop:(id)sender
{
    [_streamer stop];
}

- (void)_actionSliderProgress:(id)sender
{
    //[_streamer setCurrentTime:[_streamer duration] * [_progressSlider value]];
    [_streamer setCurrentTime:[_streamer duration] * self.playingProgress];
}

- (void)_actionSliderVolume:(id)sender
{
    //[DOUAudioStreamer setVolume:[_volumeSlider value]];
    [DOUAudioStreamer setVolume:self.playingVolume];
}

@end
